package com.conversationboard.formatter;

import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import org.joda.time.DateTimeZone;
import org.joda.time.MutableDateTime;
import org.joda.time.Period;

import com.conversationboard.model.User;

public class DateFormatter {

	public static String prettyPrint(Date date, User user) {

		TimeZone timeZone = user.getPreferences().getTimeZone();
		Locale locale = user.getLocale();

		DateFormat formatter;

		if (user.getPreferences().isHideTimeDisplay()) {
			formatter = DateFormat.getDateInstance(DateFormat.FULL, locale);
		} else {
			formatter = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.SHORT, locale);
		}

		formatter.setTimeZone(timeZone);

		return formatter.format(date);
	}


	public static String prettyPrintTime(Date date, User user, boolean forceDisplayAsRelative, boolean displayAgo) {

		boolean displayAsRelative = (forceDisplayAsRelative || user.getPreferences().isDisplayRelativeTimes());

		if (displayAsRelative) {
			if (user != null) {
				return prettyPrintTime(date, new Date(), displayAgo, false, true, user.getPreferences().getTimeZone());
			} else {
				return prettyPrintTime(date, new Date(), displayAgo, false, true, null);
			}
		} else {
			return prettyPrint(date, user);
		}
	}


	public static String prettyPrintTimeDifference(Date olderDate, Date newerDate, boolean displayAgo, boolean displayPasses, boolean displayYesterday, User user) {

		if (user != null) {
			return prettyPrintTime(olderDate, newerDate, displayAgo, displayPasses, displayYesterday, user.getPreferences().getTimeZone());
		} else {
			return prettyPrintTime(olderDate, newerDate, displayAgo, displayPasses, displayYesterday, null);
		}

	}


	private static String prettyPrintTime(Date olderDate, Date newerDate, boolean displayAgo, boolean displayPasses, boolean displayYesterday, TimeZone timeZone) {

		int seconds;
		int minutes;
		int hours;
		int days;
		int weeks;
		int months;
		int years;

		String ago = "";
		String pass = "";
		String passes = "";

		if (displayAgo) {
			ago = " ago";
		}

		if (displayPasses) {
			pass = " pass";
			passes = " passes";
		}

		MutableDateTime postTime;
		MutableDateTime today;

		/* If we've passed in a time zone, then reflect the time zone - matters for calculating what 'yesterday' means */

		if (timeZone == null) {
			postTime = new MutableDateTime(olderDate);
			today = new MutableDateTime(newerDate);
		} else {
			postTime = new MutableDateTime(olderDate, DateTimeZone.forTimeZone(timeZone));
			today = new MutableDateTime(newerDate, DateTimeZone.forTimeZone(timeZone));
		}

		Period period = null;

		if (postTime.isAfter(today)) {
			period = new Period(today, postTime);
		} else {
			period = new Period(postTime, today);
		}

		seconds = period.getSeconds();
		minutes = period.getMinutes();
		hours = period.getHours();

		/* People think differently with respect to days, weeks, e.g. yesterday is not between 24 and 48 hours ago,
		 * it's anything before midnight last night, so flatten out the comparison by changing all times to midnight
		 * and then get the period. */

		postTime.setHourOfDay(0);
		postTime.setMinuteOfHour(0);
		postTime.setSecondOfMinute(0);
		today.setHourOfDay(0);
		today.setMinuteOfHour(0);
		today.setSecondOfMinute(1);

		Period period2 = new Period(postTime, today);

		days = period2.getDays();
		weeks = period2.getWeeks();
		months = period2.getMonths();
		years = period2.getYears();

		if (years > 0) {
			if (years == 1) {
				return "1 year" + ago + passes;
			} else {
				return years + " years" + ago + pass;
			}
		} else if (months > 0) {
			if (months == 1) {
				return "1 month" + ago + passes;
			} else {
				return months + " months" + ago + pass;
			}
		} else if (weeks > 0) {
			if (weeks == 1) {
				return "1 week" + ago + passes;
			} else {
				return weeks + " weeks" + ago + pass;
			}
		} else if (days > 0) {
			if ((days == 1) && displayYesterday) {
				return "Yesterday";
			} else if (days > 1) {
				return days + " days" + ago + pass;
			} else {

				/* We're one day ago but don't want to display "Yesterday", so show hours instead */

				if (hours == 1) {
					return "1 hour" + ago + passes;
				} else {
					return hours + " hours" + ago + pass;
				}

			}
		} else if (hours > 0) {

			if (hours == 1) {
				return "1 hour" + ago + passes;
			} else {
				return hours + " hours" + ago + pass;
			}
		} else if (minutes > 0) {
			if (minutes == 1) {
				return "1 minute" + ago + passes;
			} else {
				return minutes + " minutes" + ago + pass;
			}
		} else {
			if (seconds == 1) {
				return "1 second" + ago + passes;
			} else {
				return seconds + " seconds" + ago + pass;
			}
		}

	}


	public static int getLastDayOfMonth(int year, int month) {

		if (month > 12) {
			throw new IllegalArgumentException("You cannot send a month > 12 to this method.");
		}

		if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
			return 31;
		} else if (month == 4 || month == 6 || month == 9 || month == 11) {
			return 30;
		} else {

			/* It's February. Is it a leap year? */

			if (year % 4 != 0) {
				return 28;
			} else if (year % 400 == 0) {
				return 29;
			} else if (year % 100 == 0) {
				return 28;
			} else {
				return 29;
			}
		}
	}


	/**
	 * Actually works for past times too. Need to do a bit of refactoring here.
	 * 
	 * @param time1
	 * @param time2
	 * @param timeZone
	 * @return
	 */

	public static String prettyPrintFutureTime(Date time1, Date time2, TimeZone timeZone) {

		int seconds;
		int minutes;
		int hours;
		int days;
		int weeks;
		int months;
		int years;

		MutableDateTime olderTime;
		MutableDateTime newerTime;

		/* If we've passed in a time zone, then reflect the time zone - matters for calculating what 'yesterday' means */

		if (timeZone == null) {
			olderTime = new MutableDateTime(time1);
			newerTime = new MutableDateTime(time2);
		} else {
			olderTime = new MutableDateTime(time1, DateTimeZone.forTimeZone(timeZone));
			newerTime = new MutableDateTime(time2, DateTimeZone.forTimeZone(timeZone));
		}

		Period period = null;

		if (time1.after(time2)) {
			period = new Period(newerTime, olderTime);
		} else {
			period = new Period(olderTime, newerTime);
		}

		seconds = period.getSeconds();
		minutes = period.getMinutes();
		hours = period.getHours();
		days = period.getDays();
		weeks = period.getWeeks();
		months = period.getMonths();
		years = period.getYears();

		if (years > 0) {
			if (years == 1) {
				return "1 year";
			} else {
				return years + " years";
			}
		} else if (months > 0) {
			if (months == 1) {
				return "1 month";
			} else {
				return months + " months";
			}
		} else if (weeks > 0) {
			if (weeks == 1) {
				return "1 week";
			} else {
				return weeks + " weeks";
			}
		} else if (days > 0) {
			if (days == 1) {
				return "1 day";
			} else if (days > 1) {
				return days + " days";
			}
		} else if (hours > 0) {
			if (hours == 1) {
				return "1 hour";
			} else {
				return hours + " hours";
			}
		} else if (minutes > 0) {
			if (minutes == 1) {
				return "1 minute";
			} else {
				return minutes + " minutes";
			}
		} else {
			if (seconds == 1) {
				return "1 second";
			} else {
				return seconds + " seconds";
			}
		}

		throw new IllegalStateException("Should never get here");

	}


	public static void main(String[] args) {

		Calendar calendar = new GregorianCalendar(2009, 6, 14, 00, 00, 00);

		System.out.println(calendar.getTime());
		System.out.println(DateFormatter.prettyPrintFutureTime(calendar.getTime(), new Date(), TimeZone.getTimeZone("Europe/London")));
		System.out.println(DateFormatter.prettyPrintFutureTime(calendar.getTime(), new Date(), null));

	}

}
